/*
 * Copyright (c) 2007-2020 西安交通信息投资营运有限公司 版权所有
 */

package com.xci.edu.core.service;

import com.github.lvyanyang.annotation.BindingOperateUser;
import com.github.lvyanyang.annotation.OperateLog;
import com.github.lvyanyang.sys.core.BaseSysService;
import com.xci.edu.core.entity.EduPlan;
import com.xci.edu.core.dao.EduPlanDao;
import com.xci.edu.core.filter.EduPlanFilter;
import com.github.lvyanyang.core.BoolResult;
import com.github.lvyanyang.core.PageList;
import com.github.lvyanyang.core.XCI;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;

/**
 * 培训计划服务
 * @author 张谦 zhangqian@xci96716.com
 * @since 2020-11-25 09:35:56
 */
@Service
public class EduPlanService extends BaseSysService {
    /** 培训计划数据层对象 */
    @Resource private EduPlanDao eduPlanDao;
    /** 学员信息服务 */
    @Resource private EduStudentService eduStudentService;

    /**
     * 新建培训计划
     * @param entity 培训计划实体
     */
    @BindingOperateUser
    @OperateLog(msg = "新建培训计划", module = "培训计划")
    @Transactional(rollbackFor = Exception.class)
    public BoolResult insert(EduPlan entity) {
        return save(entity, true);
    }

    /**
     * 修改培训计划
     * @param entity 培训计划实体
     */
    @BindingOperateUser
    @OperateLog(msg = "修改培训计划", module = "培训计划")
    @Transactional(rollbackFor = Exception.class)
    public BoolResult update(EduPlan entity) {
        return save(entity, false);
    }

    /**
     * 修改培训计划状态
     * @param ids    培训计划主键字符串
     * @param status 培训计划状态
     */
    @OperateLog(msg = "修改培训计划状态", module = "培训计划")
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(@NotBlank(message = "请指定培训计划主键字符串") String ids, @NotNull(message = "请指定培训计划状态") Boolean status) {
        XCI.forEachIds(ids, id -> {
            //修改培训计划状态前的校验
            BoolResult boolResult = beforeUpdateStatus(id);
            if (boolResult.isFail()) {
                XCI.throwException(boolResult);
            }
            eduPlanDao.updateStatus(id, status);
        });
    }

    /**
     * 修改培训计划状态前的校验
     *
     * @param id  培训计划主键
     */
    private BoolResult beforeUpdateStatus(Long id) {
        //查看当前 培训科目 是否有学生报名
        boolean existxStudentByEduPlanId = eduStudentService.existxByEduPlanId(id);
        if(existxStudentByEduPlanId){
            return BoolResult.fail(XCI.format("无法修改状态,原因：当前培训计划已经有学员预约！"));
        }
        return BoolResult.success();
    }


    ///**
    // * 批量保存培训计划
    // * @param entities 培训计划实体集合
    // */
    //@OperateLog(msg = "修改培训计划", module = "培训计划")
    //@Transactional(rollbackFor = Exception.class)
    //public void batchSave(List<EduPlan> entities) {
    //    for (EduPlan entity : entities) {
    //        if (entity.getId() == null || !eduPlanDao.existById(entity.getId())) {
    //            //无主键或者主键在数据库中不存在,则新建;
    //            self.save(entity, true).ifFailThrow();
    //        } else {
    //            //其他情况,则修改
    //            self.save(entity, false).ifFailThrow();
    //        }
    //    }
    //}

    /**
     * 删除培训计划
     * @param ids 培训计划主键字符串
     */
    @OperateLog(msg = "删除培训计划", module = "培训计划")
    @Transactional(rollbackFor = Exception.class)
    public BoolResult delete(@NotBlank(message = "请指定培训计划主键字符串") String ids) {
        XCI.forEachIds(ids, id -> {
            var entity = eduPlanDao.selectById(id);
            if (entity == null) return;

            //删除培训计划信息前的校验
            BoolResult boolResult = beforeSetPlanCheck(entity);
            if (boolResult.isFail()) {
                XCI.throwException(boolResult);
            }

            eduPlanDao.deleteById(entity.getId());
            logService.saveDeleteHistoryLogAsync(entity.getId(), entity);
        });
        return BoolResult.success();
    }

    /**
     * 删除培训计划信息前的校验
     *
     * @param eduPlan  培训计划对象
     */
    private BoolResult beforeSetPlanCheck(EduPlan eduPlan) {
        //查看当前状态是否是启用状态
        if(eduPlan.getStatus().equals(1)){
            return BoolResult.fail(XCI.format("当前信息启用状态，无法删除！"));
        }
        // 查看当前科目是否有人报名
//        boolean existxByEduEduPlanId=eduStudentService.existxByEduPlanId(eduPlan.getId());
//        if (existxByEduEduPlanId) {
//            return BoolResult.fail(XCI.format(" {}--无法删除,原因：当前计划已经有人！", eduPlan.getName()));
//        }
        if(eduPlan.getUseCount()>0){
            return BoolResult.fail(XCI.format(" {}--无法删除,原因：当前计划已经有人！", eduPlan.getName()));
        }
        return BoolResult.success();
    }

    ///**
    // * 是否存在指定主键的培训计划
    // * @param id 培训计划主键
    // * @return 如果存在返回true
    // */
    //public boolean existById(@NotNull(message = "请指定培训计划主键") Long id) {
    //    return eduPlanDao.existxById(id);
    //}

    ///**
    // * 是否存在指定名称的培训计划
    // * @param name      培训计划名称
    // * @param excludeId 排除的主键，如果为null则不指定排除的主键
    // * @return 如果存在返回true
    // */
    //public boolean existByName(@NotBlank(message = "请指定培训计划名称") String name, Long excludeId) {
    //    return eduPlanDao.existxByName(name, excludeId);
    //}

    /**
     * 根据主键查询单个培训计划
     * @param id 培训计划主键
     * @return 返回培训计划实体
     */
    public EduPlan selectById(@NotNull(message = "请指定培训计划主键") Long id) {
        return eduPlanDao.selectById(id);
    }

    /**
     * 是否存在指定科目的培训计划
     * @param eduCategoryId 科目主键
     * @return 如果存在返回true
     */
    public boolean existxByEduCategoryId(@NotNull(message = "请指定科目主键") Long eduCategoryId) {
        return eduPlanDao.existxByEduCategoryId(eduCategoryId);
    }

    /**
     * 查询培训计划列表
     * @param filter 过滤条件
     * @return 返回培训计划列表
     */
    public List<EduPlan> selectList(EduPlanFilter filter) {
        return eduPlanDao.selectList(filter);
    }

    /**
     * 查询培训计划分页列表
     * @param filter 过滤条件
     * @return 返回培训计划分页列表
     */
    public PageList<EduPlan> selectPageList(EduPlanFilter filter) {
        return PageList.of(eduPlanDao.selectPageList(filter));
    }

    /**
     * 查询培训计划信息(下拉框)(启用)
     *
     * @param eduCategoryId 科目主键
     * @return 培训计划信息(启用)(下拉框)
     */
    public List<EduPlan> getPlanIdAndPlanName(String eduCategoryId) {
        return eduPlanDao.getPlanIdAndPlanName(eduCategoryId);
    }


    /**
     * 保存数据,在insert和update之前和之后的校验和处理
     * @param entity  培训计划实体
     * @param created 是否新建
     */
    private BoolResult save(EduPlan entity, boolean created) {
        //新建时如果主键未指定,自动设置主键
        XCI.ifTrueAction(XCI.invalidId(entity.getId(), created), () -> entity.setId(XCI.nextId()));
        //如果简拼为空,设置简拼
        XCI.ifBlankAction(entity.getSpell(), () -> entity.setSpell(XCI.getSpell(entity.getName())));

        //新增修改 共有业务
        // 科目名称 唯一性验证
        if (eduPlanDao.existxByName(entity.getName(), created ? null : entity.getId())) {
            return BoolResult.fail(XCI.format("培训计划名称 [{}]已经存在", entity.getName()));
        }

        //更新数据库
        if (created) {
            eduPlanDao.insert(entity);
            logService.saveInsertHistoryLogAsync(entity.getId(), entity);
        } else {
            var before = eduPlanDao.selectById(entity.getId());
            //修改的业务
            if(!entity.getName().equals(before.getName())){
                return BoolResult.fail(XCI.format("计划名称不能改变！"));
            }
            if(!entity.getEduCategoryName().equals(before.getEduCategoryName())){
                return BoolResult.fail(XCI.format("计划科目不能改变！"));
            }
            if(entity.getPlanCount() < before.getUseCount()){
                return BoolResult.fail(XCI.format("计划人数不能小于已约人数！"));
            }
            eduPlanDao.update(entity);
            logService.saveUpdateHistoryLogAsync(entity.getId(), before, entity);
        }
        return BoolResult.success();
    }

    /**
     * 学员设置计划
     *      校验:
     *          1.当前计划是否已经约满
     *                  没有约满:更改已约人数
     *                  约满:返回信息
     * @param planId  计划主键
     */
    public BoolResult AddPlan(long planId) {
        EduPlan eduPlan = eduPlanDao.selectById(planId);
        Integer planCount = eduPlan.getPlanCount();
        Integer useCount = eduPlan.getUseCount();
        if(planCount <= useCount){
            return BoolResult.fail(XCI.format("{}无法预约,原因:当前计划已经约满",eduPlan.getName()));
        }
        eduPlanDao.updateUseCountById(eduPlan.getId(),eduPlan.getUseCount()+1);
        return BoolResult.success();
    }

    /**
     * 学生退档
     *
     * @param planId  计划主键
     */
    public BoolResult removePlan(long planId) {
        EduPlan eduPlan = eduPlanDao.selectById(planId);
        eduPlanDao.updateUseCountById(eduPlan.getId(),eduPlan.getUseCount()-1);
        return BoolResult.success();
    }
}